#ifndef _RENZO_RENZODERER_
#define _RENZO_RENZODERER_

#include "RenzoMustHave.h"
#include <map>
#include <vector>
using namespace std;

namespace Renzo {
// This class is exported from the Renzoderer.dll
class RENZODERER_API Renzoderer {
private:
	Renzoderer(void);
	~Renzoderer(void);
	static Renzoderer* renzo;

	/*
	 * DLL management
	 */
	typedef std::map<const char*, DynLib*> PluginDynLibList;
	PluginDynLibList loadedPluginDlls;		// plugin dlls already loaded. Tracked for unloaded

	/*
	 * Plugin management
	 */
	typedef std::vector<Plugin*> PluginInstanceList;
	PluginInstanceList installedPlugins;	// plugins already installed after loaded

	/*
	 * Plugin constructor and destructor function signature
	 */
	typedef void (*DLL_START_PLUGIN)(void);
    typedef void (*DLL_STOP_PLUGIN)(void);
	
public:
	// singleton
	static Renzoderer* instance();
	
	/*
	Load and unload plugins. 
	*/
	void loadPlugin(const char* dll);
	void unloadPlugin(const char* dll);

	/*
	Install and uninstall plugins. A plugin can only be installed into Renzoderer after it is loaded by loadPlugin function.
	*/
	void installPlugin(Plugin* p);
	void uninstallPlugin(Plugin* p);

	// let's start!
	void kickoff();

protected:
	//View* view;
	typedef std::vector<RenderSystem*> RenderSystemList;
	RenderSystemList	renderSystems;
	RenderSystem*		activeRenderSystem;
	
public:
	void addRenderSystem(RenderSystem* r);
	RenderSystem*	getActiveRenderSystem();						// get current render system
	void			setActiveRenderSystem(RenderSystem* r);	// set a render system for render
	RenderSystemList* getRenderSystems();							// get available render systems
	RenderSystem*	getRenderSystemByName(const char* name);
	void			setRenderSystemByName(const char* name);
public:
	/*
	 * Static variables that is accessible by all classses
	 */
	static Log* log; // FIXME: singleton, what's the point to let a variable here?

/*
 Startup arguments
*/
private:
	int argc;
	char** argv;
public:
	void setArguments(int argc, char* argv[]);
	void getArguments(int* argc, char*** argv);

/*
 Scene lists
 */
private:
	typedef std::vector<Scene*> SceneList;	// we have a small number of scenes at a time (< 5 or 10), so use a vector with linear search is enough
	SceneList scenes;
	Scene* activeScene;
public:
	void addScene(Scene* s);
	void setActiveScene(Scene* s);
	Scene* getActiveScene() const;

/*
 Timer
 */
private:
	Timer* timer;
public:
	Timer* getTimer() const;

/*
 Update-render-sleep
 */
public:
	int update();

/*
 Window management
 */
public:
	int getWindowWidth();
	int getWindowHeight();
	void setWindowSize(int w, int h);
protected:
	int winWidth;
	int winHeight;

/*
 Global resource management
 */
public:
	ResourceManager* getResourceManager() const;
protected:
	ResourceManager* resourceManager;

/*
 Image management
 */
public:
	ImageManager* getImageManager() const;
	void setImageManager(ImageManager* im);
protected:
	ImageManager* imageManager;

/*
 Texture management
 */
public:
	TextureManager* getTextureManager() const;
	void setTextureManager(TextureManager* tm);
protected:
	TextureManager* textureManager;

/*
 Scene management
 */
public:
	SceneManager* getSceneManager() const;
protected:
	SceneManager* sceneManager;

};
}

#endif